/*
* @(#)MaintDmsRestoreAction.java
*
* Copyright (c) 2003 DCIVision Ltd
* All rights reserved.
*
* This software is the confidential and proprietary information of DCIVision
* Ltd ("Confidential Information").  You shall not disclose such Confidential
* Information and shall use it only in accordance with the terms of the license
* agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.dms.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.dcivision.dms.DmsErrorConstant;
import com.dcivision.dms.DmsOperationConstant;
import com.dcivision.dms.bean.DmsArchive;
import com.dcivision.dms.bean.DmsArchiveDetail;
import com.dcivision.dms.bean.DmsContent;
import com.dcivision.dms.bean.DmsDocument;
import com.dcivision.dms.bean.DmsLocMaster;
import com.dcivision.dms.core.DocumentOperationManager;
import com.dcivision.dms.core.DocumentRetrievalManager;
import com.dcivision.dms.core.RootRetrievalManager;
import com.dcivision.dms.dao.DmsArchiveDAObject;
import com.dcivision.dms.dao.DmsArchiveDetailDAObject;
import com.dcivision.dms.dao.DmsContentDAObject;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemFunctionConstant;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.Utility;
import com.dcivision.framework.web.AbstractActionForm;

public class MaintDmsRestoreAction extends com.dcivision.framework.web.AbstractMaintAction {

  public static final String REVISION = "$Revision: 1.15 $";

  public static final String RESTORE_SUCCEED = "dms.label.restore_successfully";
  public static final String RESTORE_FAIL = "dms.label.restore_fail";
  public static final String RESTORE_COUNT = "dms.label.restore_count";
  public static final String RESTORE_COUNT_FAIL = "dms.label.restore_count_fail";
  public static final String RESTORE_FAIL_NOT_TARGET_FOLDER="dms.label.restore_fail_not_target_folder";
  public static final String RESTORE_FAIL_NOT_TARGET_FILE="dms.label.restore_fail_not_target_file";

  /** Creates a new instance of MaintDmsRestoreAction */
  public MaintDmsRestoreAction() {
    super();
  }

  /** getFunctionCode
   *
   * Abstract function which sub-class should implement to return the corresponding
   * function code.
   *
   * @return   The function code
   */
  public String getFunctionCode() {
    return(SystemFunctionConstant.DMS_ARCHIVE);
  }

  /** getMajorDAOClassName
   *
   * Abstract function which sub-class should implement to return the corresponding
   * major DAO class name used in this class.
   *
   * @return   The DAO class name
   */
  public String getMajorDAOClassName() {
    return("com.dcivision.dms.dao.DmsArchiveDAObject");
  }

  public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws ServletException {
    SessionContainer sessionContainer = this.getSessionContainer(request);
    Connection conn = this.getConnection(request);
    ActionForward retValue;
    MaintDmsRestoreForm maintForm = (MaintDmsRestoreForm) form;
    String opMode = maintForm.getOpMode();
    String navMode = maintForm.getNavMode();
    String errorMessage="";
    try {
      if (!Utility.isEmpty(opMode)) {
        // Set the function code for current action.

        ActionForward forward = this.retrieveFunctionCode(request, response, mapping);
        if (forward!=null) {
          return forward;
        }

        if (GlobalConstant.OP_MODE_INSERT.equals(opMode)){
          // Insert operation.
          try {
            this.insertRecord(mapping, maintForm, request, response);
            this.commit(request);
          } catch (ApplicationException appEx) {
            this.rollback(request);
            handleApplicationException(request, appEx);
          }
          if (isError(request)) {
            maintForm.setNavMode(GlobalConstant.NAV_MODE_NEW);
            retValue = mapping.findForward(GlobalConstant.NAV_MODE_NEW);
          } else {
            maintForm.setNavMode(GlobalConstant.NAV_MODE_VIEW);
            retValue = mapping.findForward(GlobalConstant.NAV_MODE_VIEW);
          }
        } else if (GlobalConstant.OP_MODE_INSERT_NEW.equals(opMode)) {
          // Insert and New operation.
          try {
            this.insertRecord(mapping, maintForm, request, response);
            this.commit(request);
            form.reset(mapping, request);
            this.init(mapping, maintForm, request, response);
          } catch (ApplicationException appEx) {
            this.rollback(request);
            handleApplicationException(request, appEx);
          }
          if (isError(request)) {
            maintForm.setNavMode(GlobalConstant.NAV_MODE_NEW);
            retValue = mapping.findForward(GlobalConstant.NAV_MODE_NEW);
          } else {
            maintForm.setNavMode(GlobalConstant.NAV_MODE_NEW);
            retValue = mapping.findForward(GlobalConstant.NAV_MODE_NEW);
          }
        } else {
          retValue = super.execute(mapping, form, request, response);
        }
      } else {
        retValue = super.execute(mapping, form, request, response);
      }
      if (Utility.isEmpty(navMode) || GlobalConstant.NAV_MODE_NEW.equals(navMode)) {
        DmsArchiveDAObject archiveDAO = (DmsArchiveDAObject) this.getMajorDAObject(request);
        if ("A".equals(maintForm.getRestoreType())) {
          DmsArchive archiveObj = (DmsArchive) archiveDAO.getObjectByID(TextUtility.parseIntegerObj(request.getParameter("archiveID")));
          maintForm.setArchiveName(archiveObj.getArchiveName());
          RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
          Integer rootID = archiveObj.getRootID();
          DmsDocument dmsRootDocument = rootRetrievalManager.getRootDocument(rootID);
          DmsLocMaster locMaster = rootRetrievalManager.getTargetLocMasterByDocument(dmsRootDocument);
          String archiveSegmentID=request.getParameter("archiveSegmentID");
          int segID=TextUtility.parseInteger(archiveSegmentID);
          String archiveSegment="";
          if(segID<10){
          	archiveSegment="00"+(new Integer(segID)).toString();
          }else if(segID>=10 && segID<100){
          	archiveSegment="0"+(new Integer(segID)).toString();
          }else{
          	archiveSegment=(new Integer(segID)).toString();
          }
          String archiveRootPath=SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_ARCHIVE_FILE_PATH); 
          if(Utility.isEmpty(archiveRootPath)){
            archiveRootPath = locMaster.getLocPath();
          }
          File file=new File(archiveRootPath+"/"+archiveObj.getArchiveName()+"/"+archiveObj.getArchiveName()+"_"+archiveSegment);
          if(file.exists()){
            maintForm.setArchiveFilePath(archiveRootPath+"/"+archiveObj.getArchiveName()+"/"+archiveObj.getArchiveName()+"_"+archiveSegment);
          }else{
            errorMessage=DmsErrorConstant.CANNOT_FIND_ARCHIVE_PHYSICAL_FILE;  
          }
        }
        
      }
    } catch (ApplicationException ex) {
      handleApplicationException(request, ex);
      return mapping.findForward(GlobalConstant.NAV_MODE_LIST);
    }finally{
      conn=null;
    }
    if(!Utility.isEmpty(errorMessage)){
      addError(request,errorMessage);   
    }
    return retValue;
  }

  public void insertRecord (ActionMapping mapping, AbstractActionForm form, HttpServletRequest request, HttpServletResponse response) throws ApplicationException {
    MaintDmsRestoreForm maintForm = (MaintDmsRestoreForm) form;

    try {
      log.debug("========= RESTORE PATH: " +maintForm.getArchiveFilePath()+ " ============");
      String archiveFilePath = maintForm.getArchiveFilePath();
      
      File rootFolder = new File(archiveFilePath);
      //check if the path specified is valid
      if ( !(rootFolder.exists() && rootFolder.isDirectory()) ){
        throw new ApplicationException(DmsErrorConstant.ARCHIVE_ROOT_NOT_EXIST);
      }

      //check if the "image" folder exists under the archive root
      String imageFilePath = archiveFilePath + "/image";
      File fileFolder = new File(imageFilePath);
      if ( !(fileFolder.exists() && fileFolder.isDirectory()) ) {
        throw new ApplicationException(DmsErrorConstant.INVALID_ARCHIVE);
      }
      //check if the "data_file.xml" file exists under the "image" folder
      String indexFilePath = imageFilePath + "/data_file.xml";
      File indexFile = new File(indexFilePath);
      if ( !(indexFile.exists() && indexFile.isFile()) ) {
        throw new ApplicationException(DmsErrorConstant.INVALID_ARCHIVE);
      }

      completeRestoreArchive(imageFilePath, indexFilePath, maintForm, request);
    //} catch (IOException e) {
    } catch (ApplicationException appEx) {
      throw appEx;
    }
  }

  private void completeRestoreArchive(String imageFilePath, String indexFilePath, MaintDmsRestoreForm form, HttpServletRequest request) throws ApplicationException {
    SessionContainer sessionContainer = this.getSessionContainer(request);
    Connection conn = this.getConnection(request);
    try{
      DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
      DocumentOperationManager docOperationManager = new DocumentOperationManager(sessionContainer, conn);
      DmsContentDAObject contentDAO = new DmsContentDAObject(sessionContainer, conn);

      //create file input stream
      FileInputStream indexIS = new FileInputStream(indexFilePath);
      InputSource input = new InputSource(indexIS);

      // Create an Document node as the root for the output.
      DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
      Document indexFile = docBuilder.parse(input);
      String selectID=request.getParameter("basicSelectedID");
      String[] basicSelectedID=TextUtility.splitString(selectID.substring(1,selectID.length()),",");
      Element rootElm = indexFile.getDocumentElement();
      if (rootElm!=null) {
        log.debug("archive_id attribute: "+ rootElm.getAttribute("archive_id"));
        String archiveIDAttr = rootElm.getAttribute("archive_id");
        if (archiveIDAttr==null || !form.getArchiveID().equals(archiveIDAttr) ) {
          // archive id in the data_fil.xml does not match the user expected one
          throw new ApplicationException(DmsErrorConstant.ARCHIVE_ID_INCORRECT);
        }

        NodeList nl = rootElm.getElementsByTagName("file");
        DmsArchiveDetailDAObject dmsArchiveDetailDAO=new DmsArchiveDetailDAObject(sessionContainer,conn);
        int count = 0;
        int errorCount = 0;
        for (int i=0; nl!=null && i<nl.getLength(); i++) {
          // process with each file element
          log.debug("element " + i + " in node list 3");
          Integer documentID, versionID;
          String physicalFileName="", logicalFileName="", versionLabel="";
          Element fileElm = (Element) nl.item(i);
          documentID = new Integer(fileElm.getAttribute("id"));
          if(checkSelected(request,basicSelectedID,documentID)){
            versionID = new Integer(fileElm.getAttribute("version_id"));
            physicalFileName = fileElm.getAttribute("name");
            NodeList fileNameList = fileElm.getElementsByTagName("file_name");
            if (fileNameList!=null && fileNameList.getLength()>0){
              Element fileNameElm = (Element) fileNameList.item(0);
              Text text1 = (Text) fileNameElm.getFirstChild();
              logicalFileName = text1.getNodeValue();
            } else {
              logicalFileName = physicalFileName;
            }
            NodeList versionLabelList = fileElm.getElementsByTagName("version_label");
            if (versionLabelList!=null && versionLabelList.getLength()>0) {
              Element versionLabelElm = (Element) versionLabelList.item(0);
              Text text2 = (Text) versionLabelElm.getFirstChild();
              versionLabel = " (" + text2.getNodeValue() + ")";
            }

            if (documentID==null || versionID==null || physicalFileName==null) {
              // critical information is missing out from the data_file.xml, can not proceed
              throw new ApplicationException(DmsErrorConstant.ARCHIVE_FILE_CORRUPTTED);
            }

            DmsDocument dmsDocRecord = docRetrievalManager.getDocument(documentID);
            //get the destination path for file storage
            String foldersDir = docRetrievalManager.getFoldersDirectories(dmsDocRecord).toString();
            //log.debug("folder directory: "+foldersDir);
            //log.debug("input file: "+imageFilePath+"/"+physicalFileName);
            
            DmsContent dmsContent = (DmsContent)contentDAO.getByContentName(physicalFileName);
            //if segmentNo is not null, directory must add the segment path (add for bug 5245 in 2006/04/28 by lee.lv )
            if (dmsContent != null && dmsContent.getSegmentNO()!=null) {
              foldersDir += DmsOperationConstant.documentPath +"/" + DmsOperationConstant.segment +  dmsContent.getSegmentNO() + "/";
            }

            try{
              if(!DmsDocument.PAPER_DOC_TYPE.equals(dmsDocRecord.getDocumentType())){
                File inputFile = new File(imageFilePath+"/"+physicalFileName);
                FileInputStream fis = new java.io.FileInputStream(inputFile);
                byte[] content = new byte[1024*1024];
                FileOutputStream fos = new java.io.FileOutputStream(foldersDir+"/"+physicalFileName);

                int bufferSize = 8192;
                byte[] buffer = new byte[bufferSize];
                int length = -1;

                while ((length = fis.read(buffer, 0, bufferSize)) != -1) {
                  fos.write(buffer, 0, length);
                }
                fos.flush();
                fos.close();
                fis.close();
              }
              DmsDocument dmsDocument = docRetrievalManager.getDocument(documentID);
              DmsDocument dmsFolder = docRetrievalManager.getDocument(dmsDocument.getParentID());
              if (GlobalConstant.RECORD_STATUS_INACTIVE.equals(dmsFolder.getRecordStatus())){
            	  addError(request,RESTORE_FAIL_NOT_TARGET_FILE,logicalFileName+versionLabel);
            	  errorCount++;
            	  continue;
              }
              else if (GlobalConstant.RECORD_STATUS_INACTIVE.equals(dmsDocument.getRecordStatus())){
            	  addError(request,RESTORE_FAIL_NOT_TARGET_FOLDER,logicalFileName+versionLabel);
            	  errorCount++;
            	  continue;
              }else{
                  docOperationManager.restoreDocumentVersion(documentID, versionID);
                  count++;
                  addMessage(request, RESTORE_SUCCEED, logicalFileName+versionLabel);
              }
//              docOperationManager.restoreDocumentVersion(documentID, versionID);
//
//              count++;
//              addMessage(request, RESTORE_SUCCEED, logicalFileName+versionLabel);

            }catch(Exception e) {
              addMessage(request, RESTORE_FAIL, logicalFileName+versionLabel);
              log.debug(e);
            }
          }
        }
        if (errorCount>0){
      	  addError(request,RESTORE_COUNT_FAIL,Integer.toString(errorCount));
        }
        addMessage(request, RESTORE_COUNT, Integer.toString(count));
        form.setNavMode(GlobalConstant.NAV_MODE_VIEW);
      } else {
        log.debug("cannot find the root element");
      }
      sessionContainer = null;
      conn = null;
      docRetrievalManager.release();
      docOperationManager.release();

    } catch (ParserConfigurationException pce) {
      log.error("ParserConfigurationException in completeRestoreArchive");
      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, pce);
    } catch (SAXException SAXe) {
      log.error("SAXException in completeRestoreArchive");
      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, SAXe);
    } catch (IOException ioe) {
      throw new ApplicationException(ioe);
    }finally{
      conn=null;
    }
  }
  
  protected boolean checkSelected(HttpServletRequest request,String[] basicSelectedID,Integer documentID) throws ApplicationException{
  	boolean result=false;
  	SessionContainer sessionContainer=this.getSessionContainer(request);
  	Connection conn=this.getConnection(request);
  	DmsArchiveDetailDAObject dmsArchiveDetailDAO=new DmsArchiveDetailDAObject(sessionContainer,conn);
  	for(int i=0;i<basicSelectedID.length;i++){
  		DmsArchiveDetail dmsArchiveDetail=(DmsArchiveDetail)dmsArchiveDetailDAO.getObjectByID(TextUtility.parseIntegerObj(basicSelectedID[i]));
  		if(documentID.equals(dmsArchiveDetail.getDocumentID())){
  			result=true;
  		}
  	}
  	return result;
  }
}
